package com.secsbrain.cmdb.web.controller;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.secsbrain.cmdb.biz.IHostService;
import com.secsbrain.common.utils.DateTimeUtils;
import com.secsbrain.cmdb.dal.model.Host;
import com.secsbrain.cmdb.dal.model.HostBare;
import com.secsbrain.cmdb.dal.model.NetworkDevice;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.baomidou.mybatisplus.plugins.Page;
import com.secsbrain.cmdb.biz.ICabinetService;
import com.secsbrain.cmdb.biz.IHostBareService;
import com.secsbrain.cmdb.biz.INetworkDeviceService;
import com.secsbrain.cmdb.biz.impl.CommonService;
import com.secsbrain.cmdb.biz.utils.ExcelExportUtil;
import com.secsbrain.common.ErrorCodeEnum;
import com.secsbrain.common.ResponseResult;
import com.secsbrain.cmdb.dal.model.Cabinet;
import com.secsbrain.cmdb.web.dto.CabinetDeploy;
import com.secsbrain.cmdb.web.dto.CabinetShelf;

/**
 * 裸机管理控制层
 * @author zhaoyi
 *
 */
@RestController
@RequestMapping("api/hostBare")
public class HostBareController{
	
    @Autowired
    IHostBareService hostBareService;
    
    @Autowired
    IHostService hostService;
    
    @Autowired
    ICabinetService cabinetService;
    
    @Autowired
    INetworkDeviceService networkDeviceService;
    
    @Autowired
    CommonService commonService;
    
	/**
	 * @api {GET} /api/hostBare/list  查询裸机列表
	 * 
	 * @apiGroup BARE
	 * @apiParam {Number{11}} [idcId]     	   机房id
	 * @apiParam {String{5}}  [clusterName]  集群
	 * @apiParam {String{20}} [ip]        	   内(公)网IP
	 * @apiParam {String{20}} [hostName]     主机名
	 * @apiParam {String{10}} [env]          应用环境
	 * @apiParam {String{20}} [relativeHost] 宿主机
	 * @apiParam {String{20}} [purpose]      主机功能
	 * 
	 * @apiSuccess {Object[]} data           	 数据列表
	 * @apiSuccess {Number} data.id           	裸机ID
	 * @apiSuccess {String} data.clusterName    集群
	 * @apiSuccess {String} data.creator      	创建人
	 * @apiSuccess {String} data.updator      	更新人
	 * @apiSuccess {String} data.createTimeStr  创建时间
	 * @apiSuccess {String} data.updateTimeStr  更新时间
	 * @apiSuccess {String} data.kernel  		系统内核，如Linux 
	 * @apiSuccess {String} data.kernelRelease  系统内核版本，如4.9.0-deepin9-amd64
	 * @apiSuccess {String} data.type  			设备类型，如VMware
	 * @apiSuccess {String} data.hostName  		主机唯一标识
	 * @apiSuccess {String} data.ip  			ip，如[10.0.0.16]，多个以,分隔
	 * @apiSuccess {String} data.host  			主机名，如kira-PC
	 * @apiSuccess {String} data.os  			操作系统，如Deepin
	 * @apiSuccess {String} data.osrelease  	操作系统版本，如('15.4.1',)
	 * @apiSuccess {String} data.saltversion  	Salt版本，如2017.7.2
	 * @apiSuccess {String} data.systemSerialnumber   SN号
	 * @apiSuccess {Number} data.numCpus  		CPU数量
	 * @apiSuccess {String} data.cpuModel  		CPU型号
	 * @apiSuccess {String} data.productname  	服务器型号，如VMware Virtual Platform
	 * @apiSuccess {String} data.osarch  		系统架构，如x86_64
	 * @apiSuccess {String} data.cpuarch  		CPU架构
	 * @apiSuccess {Number} data.memTotal  		内存大小，如7969
	 * @apiSuccess {Number} data.minionStatus  	Minion状态
	 * @apiSuccess {Number} data.delStatus  	删除状态  0-未删除，1-删除
	 * @apiSuccess {Number} data.cabinetId  	机柜ID
	 * @apiSuccess {String} data.cabinetName  	机柜名称
	 * @apiSuccess {Number} data.idcId  		机房ID
	 * @apiSuccess {String} data.rackName  		机房名称
	 * @apiSuccess {String} data.groupName  	部署分组
	 * @apiSuccess {Number} data.diskCapacity   磁盘容量
	 * @apiSuccess {String} data.env  			应用环境 
	 * @apiSuccess {String} data.comment  		备注
	 * @apiSuccess {String} data.ipPublic  		公网ip
	 * @apiSuccess {String} data.purpose  		用途
	 * @apiSuccess {String} data.manager  		负责人 
	 * @apiSuccess {String} data.relativeHost 	关联主机名
     * @apiSuccess {Number} data.istatus   		状态：0闲置，1在用，2故障，3报废
	 * @apiSuccess {Date} data.purchaseDate 	采购日期
	 * @apiSuccess {Date} data.periodDate 		保修到期
	 * @apiSuccess {String} data.assetNumber  	固定资产编号
	 * @apiSuccess {String} data.udesc  		U数 
	 * @apiSuccess {String} data.manager  		负责人 
	 * @apiSuccess {String} data.relativeHost 	关联主机名
	 * 
	 * @apiSuccess {Number} data.ihostId 	          主机ID
	 * @apiSuccess {Number} data.cpuGrainNum 	CPU颗数
	 * @apiSuccess {Number} data.cpuSlotNum 	CPU插槽数
	 * @apiSuccess {String} data.memModel 		内存型号
	 * @apiSuccess {Number} data.memNum 		内存数量
	 * @apiSuccess {Number} data.memSlotNum 	内存插槽数
	 * @apiSuccess {String} data.diskModel 		硬盘型号
	 * @apiSuccess {Number} data.diskNum 		硬盘数量
	 * @apiSuccess {Number} data.diskSlotNum 	硬盘插槽数
	 * @apiSuccess {String} data.powerModel 	电源型号
	 * @apiSuccess {Number} data.powerNum 		电源数量
	 * @apiSuccess {Number} data.powerSlotNum 	电源插槽数
	 * @apiSuccess {Number} data.netNum 		网口数量
	 * @apiSuccess {Number} data.netUseNum 		网口已用数量
	 * @apiSuccess {String} data.raidInfo 		RAID信息
   	 * 
   	 */
    @RequestMapping(value = "/list", method = RequestMethod.GET)
    public ResponseResult<?> queryList(Integer page, Integer limit, Host params) {
    	Page<HostBare> pageBean=new Page<HostBare>(page, limit);
    	Page<HostBare> pageResult=hostBareService.queryHostBarePageList(pageBean, params);
    	
    	Map<Long, String> idcMap=commonService.getIdcMap();
    	Map<Long, String> cabinetMap=commonService.getCabinetMap();
    	for(HostBare host:pageResult.getRecords()){
    		this.parseHost(host, idcMap,cabinetMap);
    	}
    	return new ResponseResult(pageResult);
    }
    
    private void parseHost(HostBare host,Map<Long, String> idcMap,Map<Long, String> cabinetMap){
    	if(host.getIdcId()!=null&&host.getIdcId()!=0){
			host.setRackName(idcMap.get(host.getIdcId()));
		}
    	if(host.getCabinetId()!=null&&host.getCabinetId()!=0){
			host.setCabinet(cabinetMap.get(host.getCabinetId()));
		}
    }
    
    /**
   	 * @api {GET} /api/hostBare/queryCabinetDeploy  查询机柜部署图
   	 * 
   	 * @apiGroup BARE
   	 * 
   	 * @apiParam {String{20}}  [clusterName]  集群
   	 * @apiParam {String{20}}  [idcId]        机房ID
   	 * 
   	 * @apiSuccess {Object[]} data             机柜列表
   	 * @apiSuccess {Number} data.id            机柜ID
   	 * @apiSuccess {String} data.physicalEquipmentName    设备部署情况，如21台/15U/6U
   	 * @apiSuccess {String} data.cabinetSerial 机柜编号，如MDC-3-A08
   	 * @apiSuccess {Object[]} data.shelfList     机架列表
   	 * @apiSuccess {Number} data.shelfList.id    U数
   	 * @apiSuccess {Number} data.shelfList.height   占用的u
   	 * @apiSuccess {String} data.shelfList.hostName 主机名
   	 * @apiSuccess {String} data.shelfList.purpose  用途
   	 * @apiSuccess {String} data.shelfList.sn       sn号
   	 * @apiSuccess {String} data.shelfList.type     设备类型，blank：空，physical：物理机，switch：交互机，router： 路由器
   	 * 
     */
    @RequestMapping(value = "/queryCabinetDeploy", method = RequestMethod.GET)
    public ResponseResult<?> queryCabinetDeploy(String clusterName,Long idcId){
    	if(StringUtils.isEmpty(clusterName)){
    		clusterName=null;
    	}
    	
    	Cabinet cabinetParam=new Cabinet();
    	cabinetParam.setIdcId(idcId);
    	
    	List<CabinetDeploy> cabinetDeployList=new ArrayList<CabinetDeploy>();
    	//查询机柜列表
    	List<Cabinet> cabinetList=cabinetService.selectList(cabinetParam);
    	for(Cabinet cabinet:cabinetList){
    		CabinetDeploy cabinetDeploy=new CabinetDeploy();
    		
    		cabinetDeploy.setId(cabinet.getId());
    		cabinetDeploy.setCabinetSerial(cabinet.getName());
    		
    		List<CabinetShelf> shelfList=new ArrayList<CabinetShelf>();

    		int serverCount=0;//设备数量
    		int useU=0;// 占用的U数
    		for(int i=1;i<=cabinet.getUcount();i++){
    			
    			Host hostParam=new Host();
        		hostParam.setCabinetId(cabinet.getId());
        		hostParam.setDelStatus(0);
        		hostParam.setType("physical");
        		hostParam.setClusterName(clusterName);
        		hostParam.setUposition(i);
        		Host host=hostService.selectOne(hostParam);
        		
        		NetworkDevice networkDeviceParam=new NetworkDevice();
        		networkDeviceParam.setCabinetId(cabinet.getId());
        		networkDeviceParam.setUposition(i);
        		NetworkDevice networkDevice=networkDeviceService.selectOne(networkDeviceParam);
        		
        		if(host!=null){
        			useU+=Integer.parseInt(host.getUdesc());
        			serverCount++;
        			
        			CabinetShelf cabinetShelf=new CabinetShelf();
        			cabinetShelf.setHostName(host.getHost());
        			cabinetShelf.setId(host.getUposition());
        			cabinetShelf.setPurpose(host.getPurpose());
        			cabinetShelf.setSn(host.getSystemSerialnumber());
        			cabinetShelf.setHeight(Integer.parseInt(host.getUdesc()));
        			cabinetShelf.setType(host.getType());
        			
        			shelfList.add(cabinetShelf);
        		}else if(networkDevice!=null){
        			useU+=networkDevice.getUdesc();
        			serverCount++;
        			
        			CabinetShelf cabinetShelf=new CabinetShelf();
        			cabinetShelf.setId(networkDevice.getUposition());
        			cabinetShelf.setPurpose(networkDevice.getComment());
        			cabinetShelf.setSn(networkDevice.getCode());
        			cabinetShelf.setHeight(networkDevice.getUdesc());
        			cabinetShelf.setType(networkDevice.getType());
        			
        			shelfList.add(cabinetShelf);
        		}else{
        			CabinetShelf cabinetShelf=new CabinetShelf();
        			cabinetShelf.setId(i);
        			cabinetShelf.setHeight(1);
        			cabinetShelf.setType("blank");
        			
        			shelfList.add(cabinetShelf);
        		}
    		}
    		
    		cabinetDeploy.setPhysicalEquipmentName(serverCount+"台/"+useU+"U/"+(cabinet.getUcount()-useU)+"U");
    		cabinetDeploy.setShelfList(shelfList);
    		
    		cabinetDeployList.add(cabinetDeploy);
    	}
    	return new ResponseResult(cabinetDeployList);
    }
    
    /**
   	 * @api {GET} /api/hostBare/export  导出裸机
   	 * 
   	 * @apiGroup BARE
   	 * 
   	 * @apiParam {String{20}}  hostName       主机名，其他字段见查询接口
   	 * 
     */
    @RequestMapping("/export")
    public void export(HttpServletResponse response,HttpServletRequest request,Host params) {
		params.setEnv(null);
    	if(StringUtils.isNotEmpty(params.getAppEnv())){
    		params.setEnv(params.getAppEnv());
    	}
    	Page<HostBare> pageBean=new Page<HostBare>(1, 10000);
    	Page<HostBare> pageResult=hostBareService.queryHostBarePageList(pageBean, params);
        
    	List<HostBare> list = pageResult.getRecords();

    	ExcelExportUtil e  =   new  ExcelExportUtil();
	    e.createRow( 0 );
        e.setCell( 0 ,  "主机" );
        e.setCell( 1 ,  "主机类型" );
        e.setCell( 2 ,  "内网IP" );
        e.setCell( 3 ,  "公网IP" );
        e.setCell( 4 ,  "主机名" );
        e.setCell( 5 ,  "主机功能" );
        e.setCell( 6 ,  "宿主机" );
        e.setCell( 7 ,  "配置" );
        e.setCell( 8 ,  "机房" );
        e.setCell( 9 ,  "应用环境" );
        e.setCell( 10 ,  "SN序列号" );
        e.setCell( 11 ,  "负责人" );
        e.setCell( 12 ,  "状态" );
        e.setCell( 13 ,  "服务器型号" );
        e.setCell( 14 ,  "采购日期" );
        e.setCell( 15 ,  "保修到期" );
        e.setCell( 16 ,  "操作系统" );
        e.setCell( 17 ,  "机柜" );
        e.setCell( 18 ,  "u数" );
        e.setCell( 19 ,  "kernel版本" );
        e.setCell( 20 ,  "CPU型号" );
        e.setCell( 21 ,  "salt版本" );
        e.setCell( 22 ,  "固定资产编号" );
        e.setCell( 23 ,  "部署分组" );
        e.setCell( 24 ,  "集群" );
        e.setCell( 25 ,  "CPU颗数/总插槽" );
        e.setCell( 26 ,  "内存条数量/总插槽" );
        e.setCell( 27 ,  "硬盘数量/总插槽" );
        e.setCell( 28 ,  "电源数量/总插槽" );
        e.setCell( 29 ,  "网口数量/总数" );
        e.setCell( 30 ,  "电源型号" );
        e.setCell( 31 ,  "RAID信息" );
        e.setCell( 32 ,  "备注" );
        
        
        Map<Long, String> idcMap=commonService.getIdcMap();
    	Map<Long, String> cabinetMap=commonService.getCabinetMap();
    	
		if (list != null && list.size() > 0) {
			for (int i =0;i < list.size();i++) {
				HostBare host = list.get(i);
	    		this.parseHost(host, idcMap, cabinetMap);

				e.createRow( i+1 );
				
				e.setCell( 0 ,  host.getHostName() );
		        e.setCell( 1 ,  host.getType());
		        e.setCell( 2 ,  host.getIp() );
		        e.setCell( 3 ,  host.getIpPublic() );
		        e.setCell( 4 ,  host.getHost() );
		        e.setCell( 5 ,  host.getPurpose() );
		        e.setCell( 6 ,  host.getRelativeHost() );
				String memTotal=BigDecimal.valueOf(Double.valueOf(host.getMemTotal())).divide(
		                BigDecimal.valueOf(1024)).setScale(2, RoundingMode.HALF_UP).toString();
		        e.setCell( 7 ,  host.getNumCpus()+"c/"+subZeroAndDot(memTotal)+"g/"+host.getDiskCapacity()+"g" );
		        e.setCell( 8 ,  host.getRackName() );
		        e.setCell( 9 ,  host.getEnv() );
		        e.setCell( 10 , host.getSystemSerialnumber() );
		        e.setCell( 11 ,  host.getManager() );
		        e.setCell( 12 ,  this.getStatusName(host.getIstatus()) );
		        e.setCell( 13 ,  host.getProductname() );
		        e.setCell( 14 ,  DateTimeUtils.parseDateAsString(host.getPurchaseDate(), "yyyy-MM-dd") );
		        e.setCell( 15 ,   DateTimeUtils.parseDateAsString(host.getPeriodDate(), "yyyy-MM-dd") );
		        e.setCell( 16 ,  host.getOs()+" "+host.getOsrelease() );
		        e.setCell( 17 ,  host.getCabinet() );
		        e.setCell( 18 ,  host.getUdesc() );
		        e.setCell( 19 ,  host.getKernelRelease() );
		        e.setCell( 20 ,  host.getCpuModel() );
		        e.setCell( 21 ,  host.getSaltversion() );
		        e.setCell( 22 ,  host.getAssetNumber() );
		        e.setCell( 23 ,  host.getGroupName() );
		        e.setCell( 24 ,  host.getClusterName() );
		        e.setCell( 25 ,  host.getCpuGrainNum()+"/"+host.getCpuSlotNum() );
		        e.setCell( 26 ,  host.getMemNum()+"/"+host.getMemSlotNum() );
		        e.setCell( 27 ,  host.getDiskNum()+"/"+host.getDiskSlotNum() );
		        e.setCell( 28 ,  host.getPowerNum()+"/"+host.getPowerSlotNum() );
		        e.setCell( 29 ,  host.getNetUseNum()+"/"+host.getNetNum() );
		        e.setCell( 30 ,  host.getPowerModel() );
		        e.setCell( 31 ,  host.getRaidInfo() );
		        e.setCell( 32 ,  host.getComment() );
			}
			
		}
		e.downloadExcel(request, response, "裸机"+ new SimpleDateFormat("yyyyMMdd").format(new Date())+".xls");
    	
    }
    
    private String getStatusName(Integer status){
    	if(status==0){
    		return "闲置";
    	}else if(status==1){
    		return "在用";
    	}else if(status==2){
    		return "故障";
    	}else if(status==3){
    		return "报废";
    	}
    	return status+"";
    }
    
    /**
     * 使用java正则表达式去掉多余的.与0
     * @param s
     * @return 
     */
    public static String subZeroAndDot(String s){
        if(s.indexOf(".") > 0){
            s = s.replaceAll("0+?$", "");//去掉多余的0
            s = s.replaceAll("[.]$", "");//如最后一位是.则去掉
        }
        return s;
    }
    
    /**
   	 * @api {POST} /api/hostBare/insert  新增裸机
   	 * 
   	 * @apiGroup BARE
   	 * 
   	 * @apiParam {String{20}}  hostName       主机名，其他字段见查询接口
   	 * 
     */
    @RequestMapping(value = "/insert", method = RequestMethod.POST)
    public ResponseResult<?> insert(@RequestBody HostBare host) {
		Assert.hasText(host.getHostName(), "hostName不能为空");

    	Host hostParam=new Host();
    	hostParam.setHostName(host.getHostName());
    	hostParam.setDelStatus(0);
		int count = hostService.selectCount(hostParam);
		if(count>0){
			return new ResponseResult<>(ErrorCodeEnum.ERROR_COMMON_PARAM.getCode(), "host："+host.getHostName()+"已存在！");
		}
    	
		//u校验
		Host hostParam2=new Host();
    	hostParam2.setCabinetId(host.getCabinetId());
    	hostParam2.setUposition(host.getUposition());
		int count2 = hostService.selectCount(hostParam2);
		if(count2>0){
			return new ResponseResult<>(ErrorCodeEnum.ERROR_COMMON_PARAM.getCode(), host.getUposition()+"u的位置已被占用！");
		}
		
		hostBareService.insertHostBare(host);
    	return new ResponseResult();
    }
    
    /**
   	 * @api {PUT} /api/hostBare/update  更新裸机
   	 * 
   	 * @apiGroup BARE
   	 * 
   	 * @apiParam {Number}  ihostId       主机ID，其他字段见查询接口
   	 * 
     */
    @RequestMapping(value = "/update", method = RequestMethod.PUT)
    public ResponseResult<?> update(@RequestBody HostBare host) {
		Assert.notNull(host.getIhostId(), "hostId不能为空");
		//u校验
		Host hostRes=hostService.selectById(host.getIhostId());
		if(hostRes==null){
			return new ResponseResult<>(ErrorCodeEnum.ERROR_COMMON_PARAM.getCode(), "主机不存在");
		}
		if(host.getCabinetId()!=null){
			hostRes.setCabinetId(host.getCabinetId());
		}
		if(host.getUposition()!=null){
			hostRes.setUposition(host.getUposition());
		}
		//u校验
		Host hostParam2=new Host();
    	hostParam2.setCabinetId(hostRes.getCabinetId());
    	hostParam2.setUposition(hostRes.getUposition());
		int count2 = hostService.selectCount(hostParam2);
		if(count2>1){
			return new ResponseResult<>(ErrorCodeEnum.ERROR_COMMON_PARAM.getCode(), hostRes.getUposition()+"u的位置已被占用！");
		}
		
    	hostBareService.updateHostBare(host);
    	return new ResponseResult();
    }
    
    /**
   	 * @api {DELETE} /api/hostBare/delete  删除裸机
   	 * 
   	 * @apiGroup BARE
   	 * 
   	 * @apiParam {Number}  ihostId         主机ID
   	 * 
     */
    @RequestMapping(value = "/delete", method = RequestMethod.DELETE)
    public ResponseResult<?> delete(@RequestBody HostBare host) {
    	hostBareService.deleteHostBare(host.getIhostId());
    	return new ResponseResult();
    }
    
}
